﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Net;

namespace UnnamedPodcastLibrary
{
    public static class FeedReader
    {
        public static bool IsFeed(string opmlFileName)
        {
            try
            {
                return XDocument.Load(opmlFileName).Descendants("channel").Any();
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static IEnumerable<Uri> ReadOpml(string opmlPathFileName)
        {
            var doc = XDocument.Load(opmlPathFileName);
            return from outline in doc.Descendants("outline")
                   where Uri.IsWellFormedUriString(outline.Attribute("xmlUrl").Value, UriKind.Absolute)
                            && outline.Attribute("type").Value.Equals("rss", StringComparison.OrdinalIgnoreCase)
                   select new Uri(outline.Attribute("xmlUrl").Value);
        }

        public static Feed ReadFeed(Uri downloadUri, string feedPathFileName)
        {
            var feed = new Feed(downloadUri)
            {
                Description = ReadFeedDescription(feedPathFileName),
                ImageUrl = ReadFeedImageUrl(feedPathFileName),
                Title = ReadFeedTitle(feedPathFileName),
            };
            feed.Episodes.AddRange(FeedReader.ReadEpisodes(feedPathFileName, downloadUri));
            return feed;
        }

        public static string ReadFeedDescription(string feedPathFileName)
        {
            var doc = XDocument.Load(feedPathFileName);
            return (from element in doc.Descendants("channel")
                             where element.Descendants("description").Count() > 0
                             select element.Element("description").Value).First();
        }

        public static string ReadFeedTitle(string feedPathFileName)
        {
            var doc = XDocument.Load(feedPathFileName);
            return (from element in doc.Descendants("channel")
                             where element.Descendants("title").Count() > 0
                             select element.Element("title").Value).First();
        }

        public static IEnumerable<Episode> ReadEpisodes(string feedPathFileName, Uri feedUrl)
        {
            var feedTitle = ReadFeedTitle(feedPathFileName);
            
            var doc = XDocument.Load(feedPathFileName);

            return from item in doc.Descendants("item")
                   where (item.Descendants("enclosure").Count() > 0)
                   && !string.IsNullOrEmpty(GetEpisodeUid(item))
                   && item.Element("enclosure") != null
                   && !string.IsNullOrEmpty((string)item.Element("enclosure").Attribute("url").Value)
                   select new Episode(
                       GetEpisodeUid(item),
                       new Uri((string)item.Element("enclosure").Attribute("url").Value),
                       feedUrl,
                       item.Element("title").Value ?? string.Empty)
                       {
                           FeedTitle = feedTitle,
                           Description = item.Element("description") != null && item.Element("description").Value as string != null ? (string)item.Element("description").Value : string.Empty,
                           FileSize = GetEnclosureLength(item.Element("enclosure")),
                           FileType = item.Element("type") == null ? Episode.FileTypeUnknown : item.Element("type").Value
                       };
        }

        static long GetEnclosureLength(XElement enclosure)
        {
            long length = Episode.FileSizeUnknown;
            
            if (enclosure.Attribute("length") == null)
                return length;

            if (long.TryParse(enclosure.Attribute("length").Value, out length))
                return length;

            return Episode.FileSizeUnknown;
        }

        static string GetEpisodeUid(XElement item)
        {
            var guid = item.Element("guid") == null ? null : item.Element("guid").Value;
            var link = item.Element("link") == null ? null : item.Element("link").Value;
            var title = item.Element("title") == null ? null : item.Element("title").Value;
            return guid ?? link ?? title;
        }

        static Int32 GetEpisodeSize(XElement item)
        {
            var length = item.Element("enclosure").Attribute("length")== null 
                ? "0" 
                : item.Element("enclosure").Attribute("length").Value;

            Int32 size;
            if (Int32.TryParse(length, out size))
                return size;
            else
                return Int32.MinValue;
        }

        internal static Uri ReadFeedImageUrl(string feedPathFileName)
        {
            var doc = XDocument.Load(feedPathFileName);

            var channelImage = from channel in doc.Descendants("channel")
                               from image in channel.Descendants("image")
                               from url in image.Descendants("url")
                               where url.Value as string != null
                               && Uri.IsWellFormedUriString((string)url.Value, UriKind.Absolute) 
                               select url;

            if (channelImage.Any())
                return new Uri(channelImage.First().Value);

            var itunesImage = from element in doc.Descendants("channel")
                              where element.Descendants("image").Count() > 0
                              select element.Attribute("href");

            return null;
        }
    }
}
